package com.example.yangdr.myapplication

import android.annotation.SuppressLint
import android.content.Context
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.text.Editable
import android.text.TextWatcher
import android.view.MotionEvent
import android.view.View
import android.widget.*
import java.io.IOException
import java.net.DatagramPacket
import java.net.DatagramSocket
import java.net.InetAddress
import java.net.SocketException
import java.util.regex.Pattern
import kotlin.concurrent.thread
import kotlin.math.PI
import kotlin.math.cos
import kotlin.math.sin


@SuppressLint("Registered")
class MainActivity : AppCompatActivity(),
                     View.OnTouchListener {
	/**IP*/
	private lateinit var socket: DatagramSocket
	private lateinit var host: String
	private lateinit var ip0: EditText
	private lateinit var ip1: EditText
	private lateinit var ip2: EditText
	private lateinit var ip3: EditText
	/**滚轮*/
	private var position = 0
	private var _last = HalfWheelLength
	/**按键*/
	private var _left = 0
	private var _right = 0
	private var _time: Long = 0
	private var click = false
	/**姿态*/
	private lateinit var filters: Array<Butterworth>
	/**显示*/
	private lateinit var _leftT: TextView
	private lateinit var _rightT: TextView
	private lateinit var _wheelT: TextView
	private lateinit var _xAxis: TextView
	private lateinit var _yAxis: TextView
	private lateinit var _zAxis: TextView
	private lateinit var accuracy: EditText

	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.activity_kotlin)
		//Socket
		try {
			socket = DatagramSocket()
		} catch (e: SocketException) {
			e.printStackTrace()
		}
		//findViewById
		ip0 = findViewById(R.id.ip0)
		ip1 = findViewById(R.id.ip1)
		ip2 = findViewById(R.id.ip2)
		ip3 = findViewById(R.id.ip3)

		_leftT = findViewById(R.id.leftState)
		_rightT = findViewById(R.id.rightState)
		_wheelT = findViewById(R.id.wheelState)
		_xAxis = findViewById(R.id.xAxis)
		_yAxis = findViewById(R.id.yAxis)
		_zAxis = findViewById(R.id.zAxis)
		accuracy = findViewById(R.id.accuracy)
		//设定恢复
		val defaultIp = arrayOf("192", "168", "137", "1")
		val preferences = getPreferences(Context.MODE_PRIVATE)
		val ip = Array(4) { preferences.getString("ip$it", defaultIp[it]) }
		host = "${ip[0]}.${ip[1]}.${ip[2]}.${ip[3]}"
		ip0.text.insert(ip0.selectionStart, ip[0])
		ip1.text.insert(ip1.selectionStart, ip[1])
		ip2.text.insert(ip2.selectionStart, ip[2])
		ip3.text.insert(ip3.selectionStart, ip[3])

		val a = preferences.getFloat("accuracy", .15f)
		accuracy.text.insert(accuracy.selectionStart, a.toString())
		filters = Array(3) { Butterworth(a) }
		//set Listener
		findViewById<EditText>(R.id.ip0).addTextChangedListener(IpGetter())
		findViewById<EditText>(R.id.ip1).addTextChangedListener(IpGetter())
		findViewById<EditText>(R.id.ip2).addTextChangedListener(IpGetter())
		findViewById<EditText>(R.id.ip3).addTextChangedListener(IpGetter())
		findViewById<EditText>(R.id.accuracy).addTextChangedListener(
				object : TextWatcher {
					/**无效输入提示*/
					private val toast = Toast.makeText(
							this@MainActivity,
							"请输入(0,1)内的数字！",
							Toast.LENGTH_SHORT
					)

					override fun onTextChanged(s: CharSequence?,
					                           start: Int,
					                           before: Int,
					                           count: Int) = Unit

					override fun beforeTextChanged(s: CharSequence?,
					                               start: Int,
					                               count: Int,
					                               after: Int) = Unit

					override fun afterTextChanged(s: Editable?) {
						//必须是(0, 1)内的数字
						val rateMatcher = Pattern
								.compile("^0?\\.\\d+")
								.matcher(s.toString())
						if (rateMatcher.find()) {
							//撤销提示
							toast.cancel()
							//更换滤波器
							val a = rateMatcher.group(0).toFloat()
							for (i in 0..2) filters[i] = Butterworth(a)
							//持久化
							val editor = getPreferences(Context.MODE_PRIVATE).edit()
							editor.putFloat("accuracy", a)
							editor.apply()
						} else
						//显示提示
							toast.show()
					}
				})
		//滚轮
		val wheelView = findViewById<ListView>(R.id.wheel)
		wheelView.adapter = ArrayAdapter(this, android.R.layout.simple_expandable_list_item_1, data)
		wheelView.setSelection(HalfWheelLength)
		_last = HalfWheelLength
		wheelView.setOnScrollListener(object : AbsListView.OnScrollListener {
			override fun onScrollStateChanged(view: AbsListView, scrollState: Int) {
				if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
					wheelView.setSelection(HalfWheelLength) //回到正中间
					_last = HalfWheelLength
				}
			}

			override fun onScroll(view: AbsListView,
			                      firstVisibleItem: Int,
			                      visibleItemCount: Int,
			                      totalItemCount: Int) {
				val temp = view.firstVisiblePosition
				if (temp == _last) return//未滚动
				if (temp > _last) {
					position--; send("ROLLING_DOWN")//向下滚动
				} else {
					position++; send("ROLLING_UP")//向上滚动
				}
				_last = temp//存储
				runOnUiThread { _wheelT.text = position.toString() }
			}
		})
		//按键行为
		findViewById<Button>(R.id.left).setOnTouchListener(this)
		findViewById<Button>(R.id.right).setOnTouchListener(this)
		findViewById<Button>(R.id.reset).setOnClickListener {
			position = 0
			_right = 0
			_left = 0
			_last = HalfWheelLength
			for (i in 0..2) filters[i].reset()
			runOnUiThread {
				_leftT.text = "0"
				_rightT.text = "0"
				_wheelT.text = "0"
			}
		}
		//文本发送功能
		val t = findViewById<EditText>(R.id.text)
		findViewById<Button>(R.id.sendText).setOnClickListener {
			send(t.text.toString())
			t.text.clear()
		}
		//传感器
		val manager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
		manager.registerListener(
				object : SensorEventListener {
					private var lastUpdate = System.nanoTime()

					override fun onSensorChanged(event: SensorEvent?) {
						val now = System.nanoTime()
						val time = 1E-9f * (now - lastUpdate)
						lastUpdate = now

						(0..2).forEach {
							filters[it](filters[it].memory + time * event!!.values[it])
						}

						val rad = -filters[1].memory
						val x0 = -filters[2].memory
						val y0 = -filters[0].memory
						val sin = sin(rad)
						val cos = cos(rad)
						val x1 = cos * x0 + sin * y0
						val y1 = cos * y0 - sin * x0

						runOnUiThread {
							val degree = DoubleArray(3) { filters[it].memory * 180 / PI }
							_xAxis.text = "x:${degree[0].toInt()}"
							_yAxis.text = "y:${degree[1].toInt()}"
							_zAxis.text = "z:${degree[2].toInt()}"
						}

						if (click) click = System.currentTimeMillis() - _time < 200
						else send("$x1 $y1")
					}

					override fun onAccuracyChanged(p0: Sensor?, p1: Int) = Unit
				},
				manager.getDefaultSensor(Sensor.TYPE_GYROSCOPE),
				SensorManager.SENSOR_DELAY_GAME)
	}

	override fun onTouch(v: View, event: MotionEvent): Boolean {
		when (when (v.id) {
			R.id.left  -> 0
			R.id.right -> 1
			else       -> return false
		} + when (event.action) {
			MotionEvent.ACTION_DOWN -> 0
			MotionEvent.ACTION_CANCEL,
			MotionEvent.ACTION_UP   -> 2
			else                    -> return false
		}) {
			0    -> {
				click = true
				_time = System.currentTimeMillis()
				send("LEFT_PRESS")
				runOnUiThread { _leftT.text = getString(R.string.pressDisplay) }
			}
			1    -> {
				send("RIGHT_PRESS")
				runOnUiThread { _rightT.text = getString(R.string.pressDisplay) }
			}
			2    -> {
				_left++
				send("LEFT_RELEASE")
				runOnUiThread { _leftT.text = _left.toString() }
			}
			3    -> {
				_right++
				send("RIGHT_RELEASE")
				runOnUiThread { _rightT.text = _right.toString() }
			}
			else -> throw RuntimeException("不存在的View触发onTouch()！")
		}
		return true
	}

	private inner class IpGetter : TextWatcher {
		override fun beforeTextChanged(
				s: CharSequence,
				start: Int,
				count: Int,
				after: Int) = Unit

		override fun onTextChanged(
				s: CharSequence,
				start: Int,
				before: Int,
				count: Int) = Unit

		override fun afterTextChanged(s: Editable) {
			host = "${ip0.text}.${ip1.text}.${ip2.text}.${ip3.text}"
			//持久化
			val editor = getPreferences(Context.MODE_PRIVATE).edit()
			editor.putString("ip0", ip0.text.toString())
			editor.putString("ip1", ip1.text.toString())
			editor.putString("ip2", ip2.text.toString())
			editor.putString("ip3", ip3.text.toString())
			editor.apply()
		}
	}

	private fun send(text: String) {
		val t = text.toByteArray()
		thread {
			try {
				val packet = DatagramPacket(t, t.size, InetAddress.getByName(host), OutPort)
				socket.send(packet)
			} catch (e: IOException) {
				e.printStackTrace()
			}
		}
	}

	/**巴特沃斯低通滤波器*/
	private class Butterworth(private val remain: Float,
	                          memory: Float = 0f) {
		var memory = memory
			private set

		operator fun invoke(data: Float) = run {
			memory = remain * memory + (1 - remain) * data
			memory
		}

		fun reset() = run { memory = 0f }
	}

	companion object {
		/** 常量  */
		private const val HalfWheelLength = 200
		private const val OutPort = 4137
		/** 显示滚轮  */
		private val data = List(2 * HalfWheelLength) { "------" }
	}
}